package com.aspire.aimini.util;

import com.aspire.aimini.constant.ErrorCode;
import com.aspire.aimini.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.List;

/**
 * 文件工具类
 *
 * @author wangguiyou
 * @date 2024-01-01
 * @description 文件处理相关工具方法
 */
@Slf4j
@Component
public class FileUtil {

    @Value("${file.upload.path:/tmp/uploads}")
    private String uploadPath;

    @Value("${file.upload.max-size:10485760}") // 10MB
    private long maxFileSize;

    @Value("${file.thumbnail.width:200}")
    private int thumbnailWidth;

    @Value("${file.thumbnail.height:200}")
    private int thumbnailHeight;

    // 支持的图片格式
    private static final Set<String> SUPPORTED_IMAGE_TYPES = Set.of(
            "image/jpeg", "image/jpg", "image/png", "image/gif", "image/bmp", "image/webp");

    // 支持的文件扩展名
    private static final Set<String> SUPPORTED_EXTENSIONS = Set.of(
            "jpg", "jpeg", "png", "gif", "bmp", "webp", "svg", "pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx");

    /**
     * 验证文件
     */
    public void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "文件不能为空");
        }

        // 检查文件大小
        if (file.getSize() > maxFileSize) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "文件大小不能超过 " + (maxFileSize / 1024 / 1024) + "MB");
        }

        // 检查文件类型
        String contentType = file.getContentType();
        String fileName = file.getOriginalFilename();
        if (!StringUtils.hasText(fileName)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "文件名不能为空");
        }

        String extension = getFileExtension(fileName).toLowerCase();
        if (!SUPPORTED_EXTENSIONS.contains(extension)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "不支持的文件类型: " + extension);
        }

        // 验证MIME类型
        if (isImage(file) && !SUPPORTED_IMAGE_TYPES.contains(contentType)) {
            throw new BusinessException(ErrorCode.PARAM_ERROR, "不支持的图片类型: " + contentType);
        }
    }

    /**
     * 保存文件
     */
    public String saveFile(MultipartFile file, Long userId) throws IOException {
        // 创建目录结构: uploadPath/userId/yyyy/MM/dd/
        String datePath = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
        String dirPath = uploadPath + "/" + userId + "/" + datePath;
        Path directory = Paths.get(dirPath);
        Files.createDirectories(directory);

        // 生成唯一文件名
        String originalFileName = file.getOriginalFilename();
        String extension = getFileExtension(originalFileName);
        String fileName = generateUniqueFileName() + "." + extension;
        String filePath = dirPath + "/" + fileName;

        // 保存文件
        Path targetPath = Paths.get(filePath);
        Files.copy(file.getInputStream(), targetPath);

        log.info("文件保存成功: {}", filePath);
        return filePath;
    }

    /**
     * 删除文件
     */
    public void deleteFile(String filePath) {
        if (!StringUtils.hasText(filePath)) {
            return;
        }

        try {
            Path path = Paths.get(filePath);
            Files.deleteIfExists(path);
            log.info("文件删除成功: {}", filePath);
        } catch (IOException e) {
            log.error("文件删除失败: {}", filePath, e);
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "文件删除失败");
        }
    }

    /**
     * 生成缩略图
     */
    public String generateThumbnail(String originalFilePath) throws IOException {
        if (!StringUtils.hasText(originalFilePath)) {
            return null;
        }

        Path originalPath = Paths.get(originalFilePath);
        if (!Files.exists(originalPath)) {
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR, "原文件不存在");
        }

        // 只为图片生成缩略图
        String extension = getFileExtension(originalFilePath).toLowerCase();
        if (!isImageExtension(extension)) {
            return null;
        }

        // 生成缩略图路径
        String thumbnailPath = originalFilePath.replace("." + extension, "_thumb." + extension);

        try {
            BufferedImage originalImage = ImageIO.read(originalPath.toFile());
            if (originalImage == null) {
                log.warn("无法读取图片: {}", originalFilePath);
                return null;
            }

            // 计算缩略图尺寸
            int originalWidth = originalImage.getWidth();
            int originalHeight = originalImage.getHeight();

            double scale = Math.min(
                    (double) thumbnailWidth / originalWidth,
                    (double) thumbnailHeight / originalHeight);

            int newWidth = (int) (originalWidth * scale);
            int newHeight = (int) (originalHeight * scale);

            // 创建缩略图
            BufferedImage thumbnailImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
            Graphics2D g2d = thumbnailImage.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.drawImage(originalImage, 0, 0, newWidth, newHeight, null);
            g2d.dispose();

            // 保存缩略图
            String formatName = extension.equals("jpg") ? "jpeg" : extension;
            ImageIO.write(thumbnailImage, formatName, new File(thumbnailPath));

            log.info("缩略图生成成功: {}", thumbnailPath);
            return thumbnailPath;

        } catch (Exception e) {
            log.error("生成缩略图失败: {}", originalFilePath, e);
            throw new IOException("生成缩略图失败", e);
        }
    }

    /**
     * 获取图片尺寸
     */
    public Map<String, Integer> getImageDimensions(String filePath) {
        Map<String, Integer> dimensions = new HashMap<>();
        try {
            BufferedImage image = ImageIO.read(new File(filePath));
            if (image != null) {
                dimensions.put("width", image.getWidth());
                dimensions.put("height", image.getHeight());
            }
        } catch (IOException e) {
            log.warn("获取图片尺寸失败: {}", filePath, e);
            dimensions.put("width", 0);
            dimensions.put("height", 0);
        }
        return dimensions;
    }

    /**
     * 计算文件哈希值
     */
    public String calculateFileHash(MultipartFile file) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] hashBytes = md.digest(file.getBytes());
            StringBuilder sb = new StringBuilder();
            for (byte b : hashBytes) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            log.error("计算文件哈希值失败", e);
            return null;
        }
    }

    /**
     * 生成下载URL
     */
    public String generateDownloadUrl(String filePath) {
        // 这里应该根据实际的文件服务配置生成URL
        // 例如：如果使用CDN，则返回CDN地址
        // 如果使用本地存储，则返回相对路径
        return "/api/files/download?path=" + Base64.getEncoder().encodeToString(filePath.getBytes());
    }

    /**
     * 获取文件类型
     */
    public String getFileType(MultipartFile file) {
        String fileName = file.getOriginalFilename();
        if (!StringUtils.hasText(fileName)) {
            return "unknown";
        }

        String extension = getFileExtension(fileName).toLowerCase();

        if (isImageExtension(extension)) {
            return "image";
        } else if (isDocumentExtension(extension)) {
            return "document";
        } else if (isVideoExtension(extension)) {
            return "video";
        } else if (isAudioExtension(extension)) {
            return "audio";
        } else {
            return "other";
        }
    }

    /**
     * 判断是否为图片文件
     */
    public boolean isImage(MultipartFile file) {
        String contentType = file.getContentType();
        return contentType != null && contentType.startsWith("image/");
    }

    /**
     * 获取文件扩展名
     */
    public String getFileExtension(String fileName) {
        if (!StringUtils.hasText(fileName)) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        return lastDotIndex > 0 ? fileName.substring(lastDotIndex + 1) : "";
    }

    /**
     * 生成唯一文件名
     */
    private String generateUniqueFileName() {
        return UUID.randomUUID().toString().replace("-", "") + "_" + System.currentTimeMillis();
    }

    /**
     * 判断是否为图片扩展名
     */
    private boolean isImageExtension(String extension) {
        return Set.of("jpg", "jpeg", "png", "gif", "bmp", "webp", "svg").contains(extension);
    }

    /**
     * 判断是否为文档扩展名
     */
    private boolean isDocumentExtension(String extension) {
        return Set.of("pdf", "doc", "docx", "xls", "xlsx", "ppt", "pptx", "txt").contains(extension);
    }

    /**
     * 判断是否为视频扩展名
     */
    private boolean isVideoExtension(String extension) {
        return Set.of("mp4", "avi", "mov", "wmv", "flv", "webm").contains(extension);
    }

    /**
     * 判断是否为音频扩展名
     */
    private boolean isAudioExtension(String extension) {
        return Set.of("mp3", "wav", "flac", "aac", "ogg").contains(extension);
    }

    /**
     * 获取文件大小的可读格式
     */
    public String getReadableFileSize(long size) {
        if (size <= 0)
            return "0 B";

        String[] units = { "B", "KB", "MB", "GB", "TB" };
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));

        return String.format("%.1f %s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }

    /**
     * 检查磁盘空间
     */
    public boolean checkDiskSpace(long requiredSpace) {
        try {
            Path uploadDir = Paths.get(uploadPath);
            long usableSpace = Files.getFileStore(uploadDir).getUsableSpace();
            return usableSpace > requiredSpace;
        } catch (IOException e) {
            log.error("检查磁盘空间失败", e);
            return false;
        }
    }

    /**
     * 清理临时文件
     */
    public int cleanTempFiles(int daysOld) {
        // 实现清理逻辑
        return 0;
    }
}